import exception.BusinessException;
import model.Item;
import model.ItemType;
import model.Order;
import model.OrderStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import repository.MemoryOrderRepository;
import repository.OrderRepository;
import service.OrderService;
import service.SimpleOrderService;
import util.TestTimeUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

public class OrderServiceTest {
    
    private OrderService orderService;
    private OrderRepository repository;
    
    // 测试商品数据
    private Item hamburger;
    private Item fries;
    private Item chickenWrap;
    private Item icedCoffee;
    private Item cola;
    private Item iceCream;
    private Item cake;
    
    @BeforeEach
    void setUp() {
        repository = new MemoryOrderRepository();
        orderService = new SimpleOrderService(repository);
        
        // 初始化商品数据
        hamburger = new Item("H001", "汉堡", 15.0, ItemType.MAIN);
        fries = new Item("F002", "薯条", 15.0, ItemType.MAIN);
        chickenWrap = new Item("W003", "鸡肉卷", 12.0, ItemType.MAIN);
        icedCoffee = new Item("C004", "冰咖啡", 10.0, ItemType.DRINK);
        cola = new Item("C005", "可乐", 8.0, ItemType.DRINK);
        iceCream = new Item("D007", "冰淇淋", 6.0, ItemType.DESSERT);
        cake = new Item("D008", "蛋糕", 12.0, ItemType.DESSERT);
    }
    
    @Test
    void testEmptyOrder() {
        // 测试空订单
        BusinessException exception = assertThrows(
            BusinessException.class, 
            () -> orderService.createOrder(Collections.emptyList(), false)
        );
        assertEquals("EMPTY_ORDER", exception.getErrorCode());
    }
    
    @Test
    void testDessertAlone() {
        // 测试甜品单独购买
        List<Item> items = Collections.singletonList(iceCream);
        
        BusinessException exception = assertThrows(
            BusinessException.class, 
            () -> orderService.createOrder(items, false)
        );
        assertEquals("NO_MAIN_DISH", exception.getErrorCode());
    }
    
    @Test
    void testNoMainDish() {
        // 测试没有主食
        List<Item> items = Arrays.asList(iceCream, cola);
        
        BusinessException exception = assertThrows(
            BusinessException.class, 
            () -> orderService.createOrder(items, false)
        );
        assertEquals("NO_MAIN_DISH", exception.getErrorCode());
    }
    
    @Test
    void testTooManyItems() {
        // 测试商品数量超限（最多5个）
        List<Item> items = Arrays.asList(
            hamburger, fries, chickenWrap, icedCoffee, cola, iceCream
        );
        
        BusinessException exception = assertThrows(
            BusinessException.class, 
            () -> orderService.createOrder(items, false)
        );
        assertEquals("TOO_MANY_ITEMS", exception.getErrorCode());
    }
    
    @Test
    void testComboDiscount() {
        // 测试套餐优惠：汉堡 + 薯条 = 25元（原价30元）
        List<Item> items = Arrays.asList(hamburger, fries);
        Order order = orderService.createOrder(items, false);
        
        assertEquals(25.0, order.getTotalPrice());
    }
    
    @Test
    void testIcedCoffeeAfter3pm() {
        // 测试冰咖啡在下午3点后不能售卖
        List<Item> items = Arrays.asList(hamburger, icedCoffee);
        
        // 模拟下午4点下单
        Order order = orderService.createOrder(items, false, TestTimeUtils.at(16, 0));
        
        // 验证冰咖啡被过滤
        assertFalse(order.getItems().stream()
            .anyMatch(i -> "冰咖啡".equals(i.getName())));
        assertEquals(15.0, order.getTotalPrice()); // 只有汉堡的价格
        
        // 验证备注
        assertTrue(order.getRemarks().stream()
            .anyMatch(r -> r.contains("冰咖啡已下架")));
    }
    
    @Test
    void testSecondDrinkHalfPrice() {
        // 测试第二杯半价
        List<Item> items = Arrays.asList(
            hamburger, 
            new Item("C005", "可乐", 8.0, ItemType.DRINK),
            new Item("C005", "可乐", 8.0, ItemType.DRINK)
        );
        
        Order order = orderService.createOrder(items, false);
        
        // 汉堡15元 + 可乐8元 + 可乐4元(半价) = 27元
        assertEquals(27.0, order.getTotalPrice());
    }
    
    @Test
    void testVipDiscount() {
        // 测试VIP折扣
        List<Item> items = Arrays.asList(hamburger, cake);
        Order order = orderService.createOrder(items, true);
        
        // (15 + 12) * 0.9 = 24.3
        assertEquals(24.3, order.getTotalPrice(), 0.001);
    }
    
    @Test
    void testOrderCancellation() {
        // 测试订单取消
        List<Item> items = Collections.singletonList(hamburger);
        
        // 创建订单
        LocalDateTime orderTime = TestTimeUtils.at(10, 0);
        Order order = orderService.createOrder(items, false, orderTime);
        
        // 尝试取消订单
        orderService.cancelOrder(order.getOrderId(), orderTime);
        
        // 验证订单状态
        Order cancelledOrder = repository.findById(order.getOrderId());
        assertEquals(OrderStatus.CANCELLED, cancelledOrder.getStatus());
    }
    
    @Test
    void testAutoCancellation() {
        // 测试订单自动取消（超过30分钟）
        List<Item> items = Collections.singletonList(hamburger);
        
        // 创建订单
        LocalDateTime orderTime = TestTimeUtils.at(10, 0);
        Order order = orderService.createOrder(items, false, orderTime);
        
        // 模拟31分钟后
        LocalDateTime cancellationTime = TestTimeUtils.plusMinutes(orderTime, 31);
        orderService.cancelOrder(order.getOrderId(), cancellationTime);
        
        // 验证订单状态
        Order cancelledOrder = repository.findById(order.getOrderId());
        assertEquals(OrderStatus.CANCELLED, cancelledOrder.getStatus());
        assertTrue(cancelledOrder.getRemarks().stream()
            .anyMatch(r -> r.contains("超时自动取消")));
    }
    
    @Test
    void testCannotCancelPaidOrder() {
        // 测试已支付订单不可取消
        List<Item> items = Collections.singletonList(hamburger);
        
        // 创建订单
        Order order = orderService.createOrder(items, false);
        
        // 将订单状态改为已支付
        repository.updateStatus(order.getOrderId(), OrderStatus.PAID);
        
        // 尝试取消订单
        BusinessException exception = assertThrows(
            BusinessException.class, 
            () -> orderService.cancelOrder(order.getOrderId())
        );
        assertEquals("CANNOT_CANCEL_PAID", exception.getErrorCode());
    }
} 